
///类型
enum motor_state_t
{
    motor_stop_state_v,
    motor_accelerate_state_v,
    motor_speed_max_state_v,
    motor_decelerate_state_v
};

struct motor_spta_t
{
    int32_t total_step_v;                               //设定运行总脉冲数。负数就往复位方向移动
    uint32_t step_counter_v;                            //已经运行的脉冲数
    uint16_t speed_v;                                   //当前速度
    uint16_t speed_max_v;                               //用户设定的最大速度
    uint32_t speed_max_threshold_v;                     //最大速度阈值，值越大，速度就能分的越精细，相当于速度百分比。用户设定的最大速度小于等于这个值
    enum motor_state_t state_v;                         //运行状态
    bool enable_interrupt_counter_v;                    //定时器中断计数的开关
    uint16_t accelerate_decelerate_action_threshold_v;  //加减速一次的频率阈值，当中断次数达到这个值后就会加减速一次
    uint16_t accelerate_decelerate_interrupt_counter_v; //加减速时的定时器中断次数计数
    uint32_t accelerate_decelerate_counter_v;           //加减速次数计数
    uint32_t accelerate_decelerate_step_v;              //加减速阶段的脉冲数
    uint32_t speed_accumulator_v;                       //速度累加器

    //以下为非必需
    GPIO_PinState reset_direction_io_level_v;                 //复位方向的方向电平
    int32_t absolute_position_step_v;                         //绝对位置，以步数为单位
    GPIO_TypeDef *step_gpio_array_v, *direction_gpio_array_v; //IO组，脉冲、方向
    uint16_t step_gpio_v, direction_gpio_v;                   //IO号，脉冲、方向

    TIM_HandleTypeDef *power_timer_p;   //电力定时器
    uint8_t power_channel_v;            //电力通道
    uint16_t power_run_v, power_hold_v; //运行功率，保持功率
    // uint8_t motor_id_v;                                       //用于查询
    // bool limit_flag;                                                                     //触发复位开关
    // float motor_1mm_setp_v;                                                              //电机走1mm所需的步数
    // GPIO_TypeDef *reset_limit_gpio_array_v; //IO组，复位限位
    // uint16_t reset_limit_gpio_v;//IO号，复位限位
    // GPIO_PinState reset_limit_io_level_v;                                                //复位限位开关被触碰的电平
};

#define curve_s_table_total_v 200 //s曲线参数个数

//初始化电机参数
void motor_arg_init(struct motor_spta_t *motor_pa, GPIO_TypeDef *step_gpio_array_va, uint16_t step_gpio_va, GPIO_TypeDef *direction_gpio_array_va, uint16_t direction_gpio_va, GPIO_PinState reset_direction_io_level_va, TIM_HandleTypeDef *power_timer_pa, uint8_t power_channel_va, uint16_t power_run_va, uint16_t power_hold_va)
{
    motor_pa->step_gpio_array_v = step_gpio_array_va;
    motor_pa->step_gpio_v = step_gpio_va;
    motor_pa->direction_gpio_array_v = direction_gpio_array_va;
    motor_pa->direction_gpio_v = direction_gpio_va;
    motor_pa->reset_direction_io_level_v = reset_direction_io_level_va;

    motor_pa->power_timer_p = power_timer_pa;
    motor_pa->power_channel_v = power_channel_va;
    motor_pa->power_run_v = power_run_va;
    motor_pa->power_hold_v = power_hold_va;
    motor_pa->speed_max_threshold_v = 0xffff;
    motor_pa->absolute_position_step_v = 0;
}

//设定数值，并启动电机
void motor_move(struct motor_spta_t *motor_pa, int32_t total_step_va, uint16_t speed_max_va, uint16_t accelerate_decelerate_action_threshold_va)
{
    if (total_step_va == 0)
        return;

    motor_pa->total_step_v = total_step_va;
    motor_pa->step_counter_v = 0;
    motor_pa->speed_v = 0;
    motor_pa->speed_max_v = speed_max_va > motor_pa->speed_max_threshold_v ? motor_pa->speed_max_threshold_v : speed_max_va;
    motor_pa->enable_interrupt_counter_v = true;
    motor_pa->accelerate_decelerate_interrupt_counter_v = 0;
    motor_pa->accelerate_decelerate_counter_v = 0;
    motor_pa->accelerate_decelerate_step_v = 0;
    motor_pa->accelerate_decelerate_action_threshold_v = accelerate_decelerate_action_threshold_va;
    motor_pa->speed_accumulator_v = 0;

    if (motor_pa->total_step_v > 0)
    {
        if (motor_pa->reset_direction_io_level_v == GPIO_PIN_SET)
            HAL_GPIO_WritePin(motor_pa->direction_gpio_array_v, motor_pa->direction_gpio_v, GPIO_PIN_RESET);
        else
            HAL_GPIO_WritePin(motor_pa->direction_gpio_array_v, motor_pa->direction_gpio_v, GPIO_PIN_SET);
    }
    else
        HAL_GPIO_WritePin(motor_pa->direction_gpio_array_v, motor_pa->direction_gpio_v, motor_pa->reset_direction_io_level_v);

    __HAL_TIM_SET_COMPARE(motor_pa->power_timer_p, motor_pa->power_channel_v, motor_pa->power_run_v); //加大功率
    motor_pa->state_v = motor_accelerate_state_v; //加速
}

//加减速控制。在中断里运行
void motor_spta_algorithm(struct motor_spta_t *motor_pa)
{
    if (motor_pa->state_v == motor_stop_state_v)
        return;

    bool carry_v = false;

    //拉低脉冲信号
    HAL_GPIO_WritePin(motor_pa->step_gpio_array_v, motor_pa->step_gpio_v, GPIO_PIN_RESET);

    motor_pa->speed_accumulator_v += motor_pa->speed_v;                   //叠加速度
    if (motor_pa->speed_accumulator_v >= motor_pa->speed_max_threshold_v) //阈值，如果当前速度达到阈值，发送脉冲的速度就达到最快了，这个阈值就是算法的最大速度
    {
        carry_v = true;
        motor_pa->speed_accumulator_v -= motor_pa->speed_max_threshold_v;
    }

    if (carry_v == true) //判断是否溢出
    {
        motor_pa->step_counter_v++;
        //拉高脉冲
        HAL_GPIO_WritePin(motor_pa->step_gpio_array_v, motor_pa->step_gpio_v, GPIO_PIN_SET);

        if (motor_pa->total_step_v > 0)
            motor_pa->absolute_position_step_v++;
        else
            motor_pa->absolute_position_step_v--;
    }

    //根据电机的状态进行工作
    switch (motor_pa->state_v)
    {
    case motor_accelerate_state_v:

        //记录加速的步数
        if (carry_v == true)
            motor_pa->accelerate_decelerate_step_v++;

        if (motor_pa->enable_interrupt_counter_v)
        {
            motor_pa->accelerate_decelerate_interrupt_counter_v++;
            if (motor_pa->accelerate_decelerate_interrupt_counter_v >= motor_pa->accelerate_decelerate_action_threshold_v)
            {
                motor_pa->accelerate_decelerate_interrupt_counter_v = 0;
                motor_pa->accelerate_decelerate_counter_v++; //计录加速的次数

                motor_pa->speed_v = curve_s_table_v[motor_pa->accelerate_decelerate_counter_v] * motor_pa->speed_max_v; //计算当前速度

                //如果加速次数达到最高次数，就停止加速，并让速度等于最大速度，再切换状态
                if (motor_pa->accelerate_decelerate_counter_v >= curve_s_table_total_v)
                {
                    motor_pa->enable_interrupt_counter_v = false;
                    motor_pa->speed_v = motor_pa->speed_max_v;
                    motor_pa->state_v = motor_speed_max_state_v;
                }
            }
        }

        //如果总步数大于1步
        if ((uint32_t)fabs(motor_pa->total_step_v) > 1)
        {
            if (motor_pa->step_counter_v >= (uint32_t)fabs(motor_pa->total_step_v) / 2) //如果已走步数大于最大步数的一半
            {
                //加速时中断计数被断，所以要调整，最后一次加速多长时间，减速的第一次的速度就维持多长时间
                motor_pa->accelerate_decelerate_interrupt_counter_v = motor_pa->accelerate_decelerate_action_threshold_v - motor_pa->accelerate_decelerate_interrupt_counter_v;
                motor_pa->state_v = motor_decelerate_state_v;
            }
        }
        else if (motor_pa->step_counter_v > 0) //只有1步就至少走1步
            motor_pa->state_v = motor_decelerate_state_v;

        break;

    case motor_speed_max_state_v:
        if ((uint32_t)fabs(motor_pa->total_step_v) - motor_pa->step_counter_v == motor_pa->accelerate_decelerate_step_v)
        {
            motor_pa->enable_interrupt_counter_v = true;
            //进入减速状态就要切换为减速状态时的最大速度
            motor_pa->accelerate_decelerate_counter_v--;
            motor_pa->speed_v = curve_s_table_v[motor_pa->accelerate_decelerate_counter_v] * motor_pa->speed_max_v; //计算当前速度
            motor_pa->state_v = motor_decelerate_state_v;
        }

        break;

    case motor_decelerate_state_v:
        if (motor_pa->enable_interrupt_counter_v)
        {
            motor_pa->accelerate_decelerate_interrupt_counter_v++;
            if (motor_pa->accelerate_decelerate_interrupt_counter_v >= motor_pa->accelerate_decelerate_action_threshold_v) //如果中断次数达到设定次数
            {
                motor_pa->accelerate_decelerate_interrupt_counter_v = 0;
                motor_pa->accelerate_decelerate_counter_v--;

                motor_pa->speed_v = curve_s_table_v[motor_pa->accelerate_decelerate_counter_v] * motor_pa->speed_max_v; //计算当前速度
            }
            if (motor_pa->speed_v <= 100)
                motor_pa->enable_interrupt_counter_v = false;
        }

        if (motor_pa->step_counter_v >= (uint32_t)fabs(motor_pa->total_step_v))
        {
            //设定电机状态
            motor_pa->state_v = motor_stop_state_v;
            __HAL_TIM_SET_COMPARE(motor_pa->power_timer_p, motor_pa->power_channel_v, motor_pa->power_hold_v); //降低功率
        }

        break;

    default:
        break;
    }
}

//运行示例
int main()
{
    tim2_init();
    tim4_init();
    HAL_TIM_Base_Start_IT(&htim2);
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);

    curve_s_init(curve_s_table_v, curve_s_table_total_v, 7);

    motor_arg_init(&motor1_v, GPIOA, GPIO_PIN_6, GPIOA, GPIO_PIN_7, GPIO_PIN_SET, &htim4, TIM_CHANNEL_2, 3, 3);
    
    while(1)
            motor_move(&motor1_v, 3200, 35000, 100);
}

void tim_call_back(TIM_HandleTypeDef *htim)
{
    if (htim == &htim2)
    {
        motor_spta_algorithm(&motor1_v);
    }
}
///内容几乎不更改的函数
//s曲线y值生成
void curve_s_init(float *buff_pa, uint16_t count_va, uint8_t pan_right_va)
{
    for (uint16_t i = 0; i < count_va; i++)
    {
        buff_pa[i] = 1.0 / (1.0 + exp(((float)pan_right_va * 2 / count_va * -i) + pan_right_va));
    }
}

void tim2_init(void)
{

    /* USER CODE BEGIN TIM2_Init 0 */

    /* USER CODE END TIM2_Init 0 */

    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};

    /* USER CODE BEGIN TIM2_Init 1 */

    /* USER CODE END TIM2_Init 1 */
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 72 - 1;
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 20 - 1;
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
    {
        Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
    {
        Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
    {
        Error_Handler();
    }
    /* USER CODE BEGIN TIM2_Init 2 */

    /* USER CODE END TIM2_Init 2 */
}

void tim4_init(void)
{

    /* USER CODE BEGIN TIM4_Init 0 */

    /* USER CODE END TIM4_Init 0 */

    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    TIM_OC_InitTypeDef sConfigOC = {0};

    /* USER CODE BEGIN TIM4_Init 1 */

    /* USER CODE END TIM4_Init 1 */
    htim4.Instance = TIM4;
    htim4.Init.Prescaler = 72 - 1;
    htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim4.Init.Period = 20 - 1;
    htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    {
        Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    {
        Error_Handler();
    }
    if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
    {
        Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
    {
        Error_Handler();
    }
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 0;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
    {
        Error_Handler();
    }
    /* USER CODE BEGIN TIM4_Init 2 */

    /* USER CODE END TIM4_Init 2 */
    HAL_TIM_MspPostInit(&htim4);
}